package mspbots.cw.client.core.data.subdata;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.client.core.AbstractToolsUtil;
import mspbots.cw.client.core.data.BaseSyncService;
import mspbots.cw.client.core.client.ClientProperties;
import mspbots.cw.common.QueryParams;
import mspbots.cw.common.RabbitKeys;
import mspbots.cw.common.ResultMsg;
import mspbots.cw.common.ResultSync;
import mspbots.cw.common.subdata.SubDataType;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.UUID;

/**
 * com.mspbots.sync.wise.service.SubdataService
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2020/3/10
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class SubDataServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    @Override
    public Mono<Void> syncSlow(ClientProperties properties) {
        return Flux.concatDelayError(this.syncPriorities(properties),
                this.syncCompanyTeamRoles(properties),
                this.syncTimeZoneSetups(properties),
                this.syncCompanyStatus(properties),
                this.syncCompanyTypes(properties))
                .then();
    }

    private void syncResult(UUID uuid, Long tenantId, SubDataType dataType, JsonNode resultNode) {
        this.sendEntity(RabbitKeys.SUB_DATA_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(uuid).id(resultNode.get("id").longValue())
                .action(dataType.name()).entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }

    private Mono<Void> syncCompanyTeamRoles(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("COMPANY-TEAM-ROLES-SYNC");
        return this.getCompanyTeamRoles(QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .contextWrite(ctx -> ctx.put("properties", properties))
                .doOnNext(resultNode -> this.syncResult(resultSync.getRequestId(), properties.getTenantId(),
                        SubDataType.COMPANY_TEAM_ROLES, resultNode))
                .then();
    }

    private Flux<JsonNode> getCompanyTeamRoles(QueryParams queryParams) {
        return this.cwWebClient.fetch("/company/teamRoles", queryParams);
    }


    private Mono<Void> syncTimeZoneSetups(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("TIME-ZONE-SETUPS-SYNC");
        return this.getTimeZoneSetups(QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .contextWrite(ctx -> ctx.put("properties", properties))
                .doOnNext(resultNode -> this.syncResult(resultSync.getRequestId(), properties.getTenantId(),
                        SubDataType.TIME_ZONE_SETUPS, resultNode))
                .then();
    }

    private Flux<JsonNode> getTimeZoneSetups(QueryParams queryParams) {
        return this.cwWebClient.fetch("/system/timeZoneSetups", queryParams);
    }

    private Mono<Void> syncCompanyStatus(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("COMPANY-STATUS-SYNC");
        return this.getCompanyStatus(QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .contextWrite(ctx -> ctx.put("properties", properties))
                .doOnNext(resultNode -> this.syncResult(resultSync.getRequestId(), properties.getTenantId(),
                        SubDataType.COMPANY_STATUS, resultNode))
                .then();
    }

    private Flux<JsonNode> getCompanyStatus(QueryParams queryParams) {
        return this.cwWebClient.fetch("/company/companies/statuses", queryParams);
    }

    private Mono<Void> syncCompanyTypes(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("COMPANY-TYPES-SYNC");
        return this.getCompanyTypes(QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .contextWrite(ctx -> ctx.put("properties", properties))
                .doOnNext(resultNode -> this.syncResult(resultSync.getRequestId(), properties.getTenantId(),
                        SubDataType.COMPANY_TYPES, resultNode))
                .then();
    }

    private Flux<JsonNode> getCompanyTypes(QueryParams queryParams) {
        return this.cwWebClient.fetch("/company/companies/types", queryParams);
    }

    private Mono<Void> syncPriorities(ClientProperties properties) {
        ResultSync resultSync = ResultSync.withDefault("PRIORITY-SYNC");
        return this.getPriorities(properties)
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(resultNode -> this.syncResult(resultSync.getRequestId(), properties.getTenantId(),
                        SubDataType.SERVICE_PRIORITIES, resultNode))
                .then();
    }


    private Flux<JsonNode> getPriorities(ClientProperties properties) {
        return this.cwWebClient.fetch("/service/priorities", QueryParams.withDefault())
                .contextWrite(ctx -> ctx.put("properties", properties));
    }


}
